import React, {memo, MouseEvent, useState, Dispatch, useEffect} from 'react';
import { useParams } from "react-router-dom";
import { isDevelopment, assign, getStore, setStore, removeStore } from '@bastet/utils';
import { IComponentType } from '@bastet/widgets';
import type { IComponent } from '@bastet/widgets';
import { BuilderInformation, BuilderWidgetPanel, BuilderEditor, useStateReducer, Context } from '../../builder';
import { getScene, updateScene, getWidgets } from '../../services';
import { resizeCustom, loadLocalWidgets, loadRemoteWidgets } from './loadDataSource';
import { widgets as testWidgetNames } from '../../widgets.json';
import {message} from "antd";

console.log('testWidgetNames: => ', testWidgetNames)
const localWidgetObject: Map<string, Promise<any>> = (import.meta as any).glob('/src/widget/**/index.tsx');
console.log('importAsync: => ', localWidgetObject);

const fetchWidget = (path: string) => fetch(path).then(res => res.text())

interface IWidgetRemote {
  id: string;
  version: string;
  name: string;
  type: string;
  renderProps: any;
  path: string; // "widgets/card.0.0.1.js"
  children: any[];
}

async function loadLocalWidgets () {
  const localWidgetMap = new Map()

  for (let [path, localWidget] of Object.entries(localWidgetObject)) {
    const widget = await localWidget();
    if (widget) {
      path = path.replace('/index.tsx', '')
      const widgetName = path.split('/').pop()
      const upperCaseName = widgetName!.toLocaleUpperCase();
      widget.settings.name = upperCaseName;
      localWidgetMap.set(upperCaseName, widget)
      console.log('widgets: => ', upperCaseName, widget)
    }
  }

  console.log('localWidgetMap: => ', localWidgetMap)
  return localWidgetMap;
}

/**
 * 当前场景中用到的所有组件
 *
 * @param widgetData
 * @param cb
 */
async function loadRemoteWidgets(widgetData: IWidgetRemote[], cb: (arg: any) => void = () => {}) {
  const remoteWidgetMap: Map<string, any> = new Map()
  const localWidgetMap = await loadLocalWidgets()
  return Promise.all(
    widgetData
      .map(widget => fetchWidget(`/${widget.path}`)
        .then(componentText => {
          // 获取组件名称
          const nameLowerCase = widget.name.toLocaleLowerCase()
          // 执行组件
          eval(componentText)

          const remoteWidget = (window as any)[`$${nameLowerCase}`];
          remoteWidget.settings.name = widget.name;
          remoteWidgetMap.set(widget.name, remoteWidget);
          delete (window as any)[`$${nameLowerCase}`]
          return { name: nameLowerCase, componentText }
        }))
  ).then(() => {
    console.log('remoteWidgetMap', remoteWidgetMap)
    /**
     * 当前需要调试的本地组件
     * 如果与服务器组件同名，则优先使用本地调试。
     */
    remoteWidgetMap.forEach(widget => {
      const { name } = widget.settings
      if (testWidgetNames.includes(name)) {
        const localWidget = localWidgetMap.get(name)
        localWidget.settings.name = name;
        // console.log('localWidget', localWidget, name)
        resizeCustom(localWidget.settings)
        widget && remoteWidgetMap.set(name, localWidget)
      } else {
        const remoteWidget = remoteWidgetMap.get(name)
        // console.log('remoteWidget', remoteWidget, name)
        // resizeCustom(remoteWidget.settings)
        remoteWidgetMap.set(name, remoteWidget)
      }
    })
    cb(remoteWidgetMap)
  })
}

function getInformation (state: any, path?: string) {
  if (path) {
    const pathArr = path.split('-');
    let data = null;
    while (pathArr.length) {
      const path: string = pathArr.shift() as string
      if (!data) {
        data = state[path]
      } else {
        data = data[path]
      }
    }
    console.log('getInformation => ', data, path)
    return data;
  }
}

function mergeWidget (remoteSetting: any, localSetting: any) {
  // console.log('remoteSetting: ', remoteSetting)
  // console.log('localSetting: ', localSetting)

  return remoteSetting?.map((widget: any) => {
    const __widget = localSetting.get(widget.name);
    if (__widget) {
      const __wgt = assign(__widget, widget);
      return {
        ...__wgt,
        children: mergeWidget(__wgt.children, localSetting)
      }
    }

    return {
      ...widget,
      children: mergeWidget(widget.children, localSetting)
    }
  })
}

// console.log(originalState)
export default memo(() => {
  const params = useParams<{id: string}>();
  const [ state, dispatch, changeField ] = useStateReducer()
  const [ scene, setScene ] = useState()
  const [ widgets, setWidgets ] = useState(new Map)
  const [ activated, setActivePath ] = useState<string>()
  const [debugging, setDebugging ] = useState<any>(getStore('debugging'))
  // const [ information, setInformation ] = useInformationReducer<IComponent>(state as IComponent[])
  const information = getInformation(state as IComponent[], activated)
  const __onClick = (_event: MouseEvent <Element>, data: IComponent) => {
    console.log('BuilderLayout: ——————————————__onClick => ', data, information?.path)
    setActivePath(data.path)
  }

  const onUpdateScene = (scene: any, widgets: any[])=> {
    updateScene({ ...scene, widgets }).then(({code, msg}) => {
      if (code === 200) message.info(msg)
    })
  }

  useEffect(() => {
    if (!params?.id) return;
    Promise.all([getScene(params.id), getWidgets()]).then(([scene, widgets]: any[] = []) => {
      // console.log('BuilderLayout: ——————————————__onClick => ', scene, widgets)

      /**
       * 请求下来的 widget
       */
      if (widgets.code === 200 && Array.isArray(widgets.data)) {
        loadRemoteWidgets(widgets.data, (widgetMap) => {
          setWidgets(widgetMap)

          /**
           * 当前的场景
           */
          if (scene.code === 200 && scene.data) {
            setScene(scene.data)
            // onUpdateScene(scene.data, widgets.data)
            /*const widgetSettings = scene.data.widgets.map((widgetSetting: { name: string; }) => {
              // 如果是开发环境，优先使用 widgets.json 中配置的组件
              if ((import.meta as any).env.DEV) {
                // 开发环境，替换为本地 localWidget.settings 配置
                // console.log('---------------', widgetSetting.name)
                const localWidget = widgetMap.get(widgetSetting.name);
                // console.log('---------------', localWidget)
                // console.log('---------------', localWidget.settings)
                if (debugging) {
                  return localWidget ? assign(widgetSetting, localWidget.settings) : widgetSetting;
                }
                return widgetSetting;
              } else {
                return widgetSetting
              }
            })*/

            if ((import.meta as any).env.DEV) {
              // 开发环境，替换为本地 localWidget.settings 配置
              dispatch(mergeWidget(scene.data.widgets, widgetMap))
            } else {
              dispatch(scene.data.widgets)
            }

            console.log(widgets, scene.data.widgets)
          }
        })
      }
    })
  }, [params, debugging])

  const onSave = () => {
    onUpdateScene(scene, state)
  }
  const onCancel = () => {

  }
  const onDevelop = () => {
    if (debugging) {
      removeStore('debugging')
      setDebugging('')
    } else {
      setDebugging('debug')
      setStore('debugging', 'debug')
    }
  }

  console.log(';;;;;;;;;;;;; => ', (import.meta as any).env.DEV, `debugging: => ${ debugging }`);
  // console.log('originalState: => ', state)
  console.log(`%cinit page data: => `, 'background: #8ce196;', { activated, information, state, widgets});
  return (
      <div className="root-builder">
        <BuilderWidgetPanel widgets={widgets} />
        <Context.Provider value={debugging}>
          <BuilderEditor
            defaultStyle={{ width: `calc(100vw - ${!information?.path ? 100 : 420}px)` }}
            state={state}
            activated={activated}
            dispatch={dispatch as Dispatch<any>}
            widgets={widgets}
            onClick={__onClick}
            onSave={onSave}
            onCancel={onCancel}
            onDevelop={onDevelop}
          />
        </Context.Provider >
        {
            information?.path && (
                <BuilderInformation
                    information={information}
                    dispatch={changeField as Dispatch<any>}/>
            )
        }
      </div>
  )
})
